{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<p style=\"text-align: center;font-size: 33px;font-weight:bold;\"> <span style=\"color:DarkGoldenrod\">&lt;&lt; C程序的基本要素 &gt;&gt;</span></p>\n",
    "<p style=\"text-align: center;font-size: 25px;font-weight:bold;\"> <span style=\"color:Goldenrod\">&lt;&lt; Programming Basics using C Language  &gt;&gt;</span></p>\n",
    "<p style=\"text-align: right; font-size:15px; font-weight:normal\">----千里之行，基于硅步</p>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 运算符与表达式\n",
    "* 算术运算符与算术表达式\n",
    "* 逻辑、关系运算符与逻辑、关系表达式\n",
    "* 逗号运算符与逗号表达式 \n",
    "* 按位运算符\n",
    "* 强制类型转换与隐含类型转换\n",
    "* 运算符的优先级与结合性\n",
    " "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 算术运算符与算术表达式\n",
    "+、-、*、/、%（取余）<br>\n",
    "* 浮点数变量与整型变量运算，结果为浮点数\n",
    "* 等长无符号整形与有符号整形运算，结果是什么类型就是什么类型\n",
    "* 短类型变量与长类型变量运算，结果为长类型\n",
    "* 算术表达式的优先级与数学定义一样。 \n",
    "* 多个一元+，-算术运算符的优先级为从右到左\n",
    "* 多个二元+，-，*，/，%算术运算符的优先级从左到右; *、/、%算术运算符的优先级较高\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#include <stdio.h>\n",
    "int main(){\n",
    "    \n",
    "    int   ia =33;\n",
    "    float fb = 44.66;\n",
    "    __typeof__ (ia+fb) c=ia+fb;\n",
    "    printf(\"%f\\n\",c);\n",
    "   \n",
    "    unsigned char ca=22;\n",
    "    signed   char cb=-46;\n",
    "    printf(\"%d\\n\",ca+cb);\n",
    "    signed char cd = 127;\n",
    "    unsigned char  ce = 45;\n",
    "    printf(\"%d\\n\",cd+ce);\n",
    "        \n",
    "    short sc = 517;\n",
    "    char  sd =  124;\n",
    "    printf(\"%d\\n\",sc+sd);\n",
    "    \n",
    "   \n",
    "    printf(\"%f\\n\",100.0/4/3-(3*6+44%16));\n",
    "    \n",
    "    \n",
    "    int i =4;\n",
    "    printf(\"%d\\n\",5-i++);\n",
    "    \n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 例：判断某一个年份是否为闰年\n",
    "解析： 当100不能够整除该年份时，若4能够整除该年份则为闰年<br>\n",
    "      或400能够整除该年份时，亦为闰年"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#include <stdio.h>\n",
    "int main(){\n",
    "    int year = 2018;\n",
    "    printf(\"Year %d is %s leap year\",year,(year%4==0&&year%100!=0)||year/100%4==0?\"a\":\"not a\");\n",
    "    return 0;\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 逻辑、关系运算符与逻辑、关系表达式\n",
    "* 基本逻辑运算符(l-op)\n",
    "！、&&、|| <br>\n",
    "(expr)&&(!expr) $\\equiv$ 0 <br>\n",
    "(expr)||(!expr)  $\\equiv$ 1 <br>\n",
    "(expr)的值要么为0，要么为1<br>\n",
    "expr 为嵌套定义，永远有拆分为expr1(!、&&、||)expr2 <br>\n",
    "二元基本逻辑运算符&&、||的运算次序为从左向右<br>\n",
    "(expr1)&&(expr2) 一旦确定（expr1）的值为0，则确定整个表达式的值为0<br>  \n",
    "(expr1)||(expr2) 一旦确定（expr1）的值为1，则确定整个表达式的值为1<br>\n",
    "!(expr)的运算次序为从右向左<br>\n",
    "* 关系运算符(r-op)\n",
    "\\>、\\<、==、\\<=、\\>=   <br>  (a>=b)&&(a<=b)\n",
    "r-expr 的运算结果才应该代入expr，expr不该代入r-expr<br>\n",
    "(r-expr1) r-op (r-expr2) 有定义无意义 <br>\n",
    "!(r-expr) 或 (r-expr1) l-op (r-expr2) 才有意义<br>\n",
    "永远不要花费大量的时间去抠细节，用（）写清楚逻辑关系就可以<br>\n",
    "* 条件表达式\n",
    "exp-a?(exp-b?b1:b2):c;<br>\n",
    "a 的值只有(0,1), 可写为`关系表达式`、`逻辑表达式`、`由关系表达式组成的逻辑表达式`<br>\n",
    "(a?b:c) 当a的值为1时，表达式的值为b,否则表达式的值为0 <br>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "//demo htoa_m   将16进制数表达的字符串转换为整形\n",
    "#include <stdio.h>\n",
    "int lower(int c)\n",
    "{\n",
    "if(c >= 'A' && c <= 'F')\n",
    "return c + 'a' - 'A';\n",
    "else\n",
    "return c;\n",
    "}                                       \n",
    "int htoa_m(char hex[]){; //hex= abcd;   loopto('c') digit= a*16+b equalto     digit = (a*16+b)*16+c //\n",
    "    int digit=0,tail;               //    loopto('d') digit=digit*16+d equalto  digit = ((a*16+b)*16+c)*16+d = a*16^3 +b*16^2 +c*16+d \n",
    "    for(int i=0;hex[i]!='\\0';i++,digit=digit+tail){   \n",
    "       \n",
    "       hex[i]=lower(hex[i]); \n",
    "                                                                  \n",
    "       tail  = (hex[i]>='a'&&hex[i]>='f')?(hex[i]-'a'+10):(hex[i]-'0');\n",
    "       digit = digit*16;\n",
    "       //digit = digit<<4;\n",
    "       \n",
    "      }\n",
    "    \n",
    "    return digit;\n",
    "}\n",
    "\n",
    "int main(){\n",
    "    char hex[]=\"1Ff\";\n",
    "    printf(\"%d\",htoa_m(hex));\n",
    "    return 0;\n",
    "}\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 逗号运算符与逗号表达式\n",
    "* 逗号运算符号是C语言中的特殊运算符号<br> ((exp1,exp2,exp3)...,expn,(exp21,exp22,exp23..,exp2n))\n",
    "* exp1,exp2,exp3 等价于exp1; exp2; return exp3<br>\n",
    "* 一般用来缩短代码，使代码看起来紧凑<br>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#include <stdio.h>\n",
    "int main(){\n",
    "//    int i=0;\n",
    "//    printf(\"%d,%d\\n\",(i++,i--),i); //\n",
    "//    return 0;\n",
    "     for(int i=1,j=10;i<j;)  //计数变量 i,j \n",
    "         printf(\"i=%d,j=%d\\n\",i++,j--); //思考，是否可以将 \"int i=1, j=10\" 放到循环体内？\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 赋值运算符号与赋值表达式\n",
    "* 赋值表达式的值为等号右边的运算结果\n",
    "* 赋值表达式的运算次序为从到左\n",
    "* 赋值表达式的作用同样是缩短代码\n",
    "\n",
    "* 自增、自减运算符号<br>\n",
    "  (i++)、(i--)、(++i)、(--i)<br>   \n",
    "  a+=b、a-=b<br>              a=a op exp; a*=b a/=b a%=b \n",
    "* 自运算<br>                                           \n",
    "  a = a (op) b  当$\\text{op} \\notin \\{=,\\text{r-op},\\text{l-op}\\}$时，可写为：<br>\n",
    "  a(op)=b<br>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 按位运算符\n",
    "～、|、&、^、\\>\\>、\\<\\< <br>          \n",
    "按位运算符可理解位变量的位操作符号<br>                                 \n",
    "一元操作符~的含义为`变量的各二进制位均取反`<br>                 \n",
    "二元非对称`位操作符`\\>\\>的含义为`变量的各二进制位均向右移动n位，n为右元`<br>    \n",
    "二元非对称`位操作符`\\<\\<的含义为`变量的各二进制位均向左移动n位，n为左元`<br>        \n",
    "二元对称`位操作符` & 的含义为`将左、右元各对应二进制位进行与运算`<br>\n",
    "二元对称`位操作符` | 的含义为`将左、右元各对应二进制位进行或运算`<br>             \n",
    "二元对称`位操作符` ^ 的含义为`将左、右元各对应二进制位进行异或运算`<br>            \n",
    "按位运算符可参与自运算<br>    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#include <stdio.h>\n",
    "int main(){\n",
    "    int a = 89;\n",
    "    int b = -43;\n",
    "    a^=b;\n",
    "    b^=a;\n",
    "    a^=b;\n",
    "    printf(\"a is %d now; b is %d now\\n\",a,b);\n",
    "    printf(\"~a is %d\\n\",~a);\n",
    "    printf(\"~(a-1) is %d\\n\",~(a-1));\n",
    "    printf(\"a >>1 is %d\\n\",a>>1);\n",
    "    printf(\"a <<1 is %d\\n\",a<<1);//不要简单的以为就是*2. \n",
    "    printf(\"a is %x, a & 0X000000FF is %x\",a,a&0X000000FF);\n",
    "    \n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 强制类型转换\n",
    "算术表达式的结果类型总取表达式中最复杂、位长最长的类型<br>\n",
    "为达到某种需要，有时许需要降低变量类型的复杂度于长度<br>\n",
    "浮点数转整型的结果为**向0取整**<br>\n",
    "长类型转短类型的结果为取最后n位，n位断类型字长<br>\n",
    "double转float仅仅降低精度，不需详细讨论<br>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#include <stdio.h>\n",
    "int main(){\n",
    "    short a  =65535;     \n",
    "    printf(\"%d\\n\",(unsigned char)a);\n",
    "    \n",
    "    double b = -76.834;\n",
    "    printf(\"%d\\n\",(int)b);    \n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 运算符的优先级与结合性\n",
    "不需要了解的太清楚，不行就加()确定次序<br>\n",
    "<table>\n",
    "<tr><th>符号</th> <th>计算次序</th></tr>\n",
    "<tr><td> !&nbsp;&nbsp;&nbsp;&nbsp; ~&nbsp;&nbsp;&nbsp;&nbsp; ++&nbsp;&nbsp;&nbsp;&nbsp; --&nbsp;&nbsp;&nbsp;&nbsp; +&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp; (type)&nbsp;&nbsp;&nbsp;&nbsp; sizeof</td><td> 从右至左</td></tr>\n",
    "<tr><td>=&nbsp;&nbsp;&nbsp;&nbsp; +=&nbsp;&nbsp;&nbsp;&nbsp; -=&nbsp;&nbsp;&nbsp;&nbsp; *=&nbsp;&nbsp;&nbsp;&nbsp; =&nbsp;&nbsp;&nbsp;&nbsp; %=&nbsp;&nbsp;&nbsp;&nbsp; &=&nbsp;&nbsp;&nbsp;&nbsp; ^=&nbsp;&nbsp;&nbsp;&nbsp; |=&nbsp;&nbsp;&nbsp;&nbsp; &lt;&lt;=&nbsp;&nbsp;&nbsp;&nbsp; &gt;&gt;=</td><td>从右至左</td></tr>\n",
    "<tr><td>, </td><td>编译器行为</td></tr> \n",
    "<tr><td>其他</td><td>从左至右</td></tr>     \n",
    "<table>    \n",
    "    \n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```C \n",
    "    int b =0;\n",
    "    //int a = g() +f();  //合法不合理，先计算g或先计算f是编译器行为\n",
    "    int temp = g();\n",
    "    int a = temp+f();\n",
    "    \n",
    "    char c[]=\"abc\";\n",
    "    char c[b]=b++ ;  //合法不合理，b先自增还是先取b的值是编译器型位\n",
    "    \n",
    "    \n",
    "    n++;\n",
    "    printf(\"%d,%f\\n\",n,pow(2,n)); //合法不合理，n++与pow(2,n)的先后次序还是编译器行为\n",
    "    \n",
    "```    \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 关于指针、数组的补充\n",
    "* char a[m][n];       \n",
    "* char (*a)[n];    \n",
    "* char a[];        \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```C\n",
    "#include <stdio.h>\n",
    "int* cumsum(int a[],int K){\n",
    "    for(int i=1;i<K;i++)\n",
    "        a[i]+=a[i-1];\n",
    "    return a;\n",
    "}\n",
    "\n",
    "\n",
    "int main(){\n",
    "    int b[6]={0,1,2,3,4,5};\n",
    "    int c =6;\n",
    "    int* r  =cumsum(b,c);  \n",
    "    \n",
    "    printf(\"r%s b\\n\",r==b?\" is equal to\":\" is not equal to \");\n",
    "    for(int i=0;i<6;i++) printf(\"%d \",b[i]); printf(\"\\n\"); // b[k] have changed!\n",
    "    return 0;\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#include <stdio.h>\n",
    "int* cumsum(int a[],int K){\n",
    "    for(int i=1;i<K;i++)\n",
    "        a[i]+=a[i-1];\n",
    "    K=K-1;\n",
    "    return a;\n",
    "}\n",
    "int main(){\n",
    "    int b[6]={0,1,2,3,4,5};\n",
    "    int K=6;\n",
    "    int* r  =cumsum(b,K);\n",
    "    printf(\"r%s b\\n\",r==b?\" is equal to\":\" is not equal to \");\n",
    "    for(int i=0;i<6;i++) printf(\"%d \",b[i]); printf(\"\\n\");\n",
    "    printf(\"K%s 6\\n\",K==6?\" is equal to\":\" is not equal to \");\n",
    "    return 0;\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 习题： \n",
    "1.  使用C语言操作数组a={0,1,2,3,4,5}，操作后要求$a[k](\\text{after})=\\sum_{i=k}^{5} a[i](\\text{before})$。before, after分别代表操作前、操作后。\n",
    "2.  使用C语言生成100个数的`斐波那切`序列 (1,1,2,3,5,8.....) 注意 a[k]=a[k-1]+a[k-2]。\n",
    "3.  打印习题(2)生成数组中符合ascii码定义数值范围的字符。 \n",
    "4.  编写一个函数，该函数的第一个参数为数组，第二、三个参数为数组下标。 函数的功能则为调换第二、三个参数指定的数组变量（要求该函数内部不使用附加变量）。\n",
    "5.  尝试编写变量值交换、数组打印函数(print_n)的`预编译替换代码`。\n",
    "6.  尝试写出能够将**含义为8进制数的字符串**转换为其所对应的**整型值**的代码。参考课件中的htoa_m函数  \n",
    "7.  定义四个变量a=10,b=66, c=33,d=127. 打印`100个数的斐波那切`序列中符合条件`大于a,小于b` 或`大于c，小于d`的值。\n",
    "8.  给定变量int d=4567, 请取出该变量第3到15个二进制位（除3到15位保留外，其余位全部置零），并将其写入一个短整型变量中。(附加，不使用&运算符) \n",
    "9.  尝试自行解释以下代码（对代码添加注释），在理解基础算法的前提下上改进以下代码。(对高斯-塞尔德算法不作要求！）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// 选择排序法\n",
    "#include <stdio.h>\n",
    "void print_n(int arr[], int n){\n",
    "for(int i=0;i<n;i++) printf(\"%d  \",arr[i]);\n",
    "printf(\"\\n\");\n",
    "}\n",
    "void selectn(int arr[],int n){\n",
    "for(int i=0;i<n;i++)\n",
    "if(arr[i]>arr[n]){\n",
    "int temp = arr[i];\n",
    "arr[i]   = arr[n];\n",
    "arr[n]     = temp;\n",
    "} \n",
    "}\n",
    "int main(){\n",
    "int arr[17]={45,23,12,-15,76,34,77,23,-66,34,89,20,33,56,79,-21,-3};\n",
    "for(int n=16;n>=0;n--)\n",
    "{\n",
    "selectn(arr,n);\n",
    "print_n(arr,17);\n",
    "}\n",
    "return 0;\n",
    "}\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "//插入排序法\n",
    "#include <stdio.h>\n",
    "void swap(int* a, int*b){\n",
    "int tmp = *a;\n",
    "*a      = *b;\n",
    "*b      = tmp;\n",
    "}\n",
    "void print_n(int arr[], int n){\n",
    "for(int i=0;i<n;i++) printf(\"%d  \",arr[i]);\n",
    "printf(\"\\n\");\n",
    "}\n",
    "void insertn(int arr[],int n,int N){\n",
    "for(int j=n;j<(N-1);j++)\n",
    "if(arr[j]>arr[j+1])\n",
    "swap(&arr[j],&arr[j+1]);\n",
    "}\n",
    "\n",
    "\n",
    "int main(){\n",
    "int arr[17]={45,23,12,-15,76,34,77,23,-66,34,89,20,33,56,79,-21,-3};\n",
    "for(int n=16;n>=0;n--)\n",
    "{\n",
    "insertn(arr,n,17);\n",
    "print_n(arr,17);\n",
    "}\n",
    "return 0;\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "//冒泡排序法\n",
    "#include <stdio.h>\n",
    "void swap(int* a, int*b){\n",
    "int tmp = *a;\n",
    "*a      = *b;\n",
    "*b      = tmp;\n",
    "}\n",
    "void print_n(int arr[], int n){\n",
    "for(int i=0;i<n;i++) printf(\"%d  \",arr[i]);\n",
    "printf(\"\\n\");\n",
    "}\n",
    "void bubble(int arr[],int n){\n",
    "for(int i=0;i<n;i++)\n",
    "if(arr[i]>arr[i+1]) swap(&arr[i],&arr[i+1]);\n",
    "}\n",
    "int main(){\n",
    "int arr[17]={45,23,12,-15,76,34,77,23,-66,34,89,20,33,56,79,-21,-3};\n",
    "for(int n=16;n>=0;n--)\n",
    "{\n",
    "bubble(arr,n);\n",
    "print_n(arr,17);\n",
    "}\n",
    "return 0;\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "//%cflags:-lm\n",
    "//Gauss-Seidal 高斯-塞尔德算法（示意而已！）\n",
    "#include <stdio.h>\n",
    "#include <math.h>\n",
    "#include <malloc.h>\n",
    "void Gauss_Siedal1(const float (*A)[5],const float* Y,float x[],int K){\n",
    "float s=0;\n",
    "for(int i=0;i<K;i++){\n",
    "    for(int j=0;j<K;j++){\n",
    "        if(!(j==i)) s+=A[i][j]*x[j];\n",
    "    }\n",
    "    x[i]= (Y[i]-s)/A[i][i];\n",
    "    s   = 0;\n",
    "    }\n",
    "}\n",
    "\n",
    "float evalue_AXY(const float (*A)[5],const float* Y,float x[],int K){\n",
    "    float sum  = 0;\n",
    "    float s    = 0;\n",
    "    for(int i=0;i<K;i++){\n",
    "        for(int j=0;j<K;j++) s+=A[i][j]*x[j];\n",
    "        s    = pow(Y[i]-s,2);\n",
    "        sum += s;\n",
    "        s    = 0;\n",
    "    }\n",
    "    return sum;\n",
    "}\n",
    "\n",
    "\n",
    "int main(){\n",
    "    float A[][5] ={{5.7,0.5,0.7,2.3,4.4},\n",
    "                  {0.5,5.7,0.3,0.2,3.6},\n",
    "                  {0.7,0.3,5.7,0.3,1.5},\n",
    "                  {2.3,0.2,0.3,5.7,0.7},\n",
    "                  {4.4,3.6,1.5,0.7,5.7}};\n",
    "    float Y[]   = {0.5,1.1,2.4,4.5,0.2};\n",
    "    \n",
    "    float x[5];\n",
    "    for(int i=0;i<5;i++) x[i]=0;\n",
    "    float eval;\n",
    "    for(int i=0;i<100;i++){\n",
    "    Gauss_Siedal1(A,Y,x,5);\n",
    "    eval = evalue_AXY(A,Y,x,5);\n",
    "    printf(\"x is \");\n",
    "    for(int j=0;j<5;j++) printf(\"%f \", x[j]);\n",
    "    printf(\"\\n\");\n",
    "    printf(\"|| Y-Ax||^2 is %f after %d iteration!\\n\",eval,i+1);    \n",
    "    }\n",
    "    \n",
    "    return 0;\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "10. （5，7到9）不作要求，为附加题。 另外请尽量自行完成习题。课堂补遗（请以文字说明将浮点数强制类型转换为整型过程中，向零取整的涵义）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "C",
   "language": "c",
   "name": "c"
  },
  "language_info": {
   "file_extension": ".c",
   "mimetype": "text/plain",
   "name": "c"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
